package com.guguskins.back.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.guguskins.back.common.constant.InventoryConstant;
import com.guguskins.back.common.constant.PrizeType;
import com.guguskins.back.common.constant.RecordConstant;
import com.guguskins.back.common.exception.GlobalMsgException;
import com.guguskins.back.entity.*;
import com.guguskins.back.entity.vo.UserInviteVo;
import com.guguskins.back.mapper.GuUserInviteMapper;
import com.guguskins.back.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 用户邀请详情表 服务实现类
 * </p>
 *
 * @author mybatis-plus
 * @since 2021-06-01
 */
@Service
public class GuUserInviteServiceImpl extends ServiceImpl<GuUserInviteMapper, GuUserInvite> implements GuUserInviteService {

    @Autowired
    private GuUserInviteMapper userInviteMapper;

    @Autowired
    private GuInviteLevelService inviteLevelService;

    @Autowired
    private GuInviteNumService inviteNumService;

    @Autowired
    private GuUserService userService;

    @Autowired
    private GuSystemConfigService systemConfigService;

    @Autowired
    private GuBoxService boxService;

    @Autowired
    private GuPropService propService;

    @Autowired
    private GuRecordService recordService;

    @Autowired
    private GuInventoryService inventoryService;

    @Autowired
    private GuPropNumService propNumService;

    @Autowired
    private GuGoodsService goodsService;

    @Override
    public UserInviteVo getList(Long userId) {
        UserInviteVo userInviteVo = new UserInviteVo();
        GuSystemConfig systemConfig = systemConfigService.getSystemConfig();

        //邀请连接
        userInviteVo.setInviteUrl(systemConfig.getConfigUri());

        //获取奖励说明
        List<GuInviteLevel> inviteLevels = inviteLevelService.list(new LambdaQueryWrapper<GuInviteLevel>() {
            {
                orderByAsc(GuInviteLevel::getLevelValue);

            }
        });
        userInviteVo.setInviteLevels(inviteLevels);
        //获取邀请人数奖励
        List<GuInviteNum> inviteNums = inviteNumService.list(new LambdaQueryWrapper<GuInviteNum>() {
            {
                orderByAsc(GuInviteNum::getInviteNum);
            }
        });
        userInviteVo.setMaxInviteNum(inviteNums.stream().map(GuInviteNum::getInviteNum).reduce(Integer::max).orElse(100));
        inviteNums = this.initInviteNums(inviteNums);

        //初始化数据，给未登录显示
        this.initUserInviteVo(userInviteVo, inviteLevels);

        //如果登录，获取邀请成功的列表
        if (!ObjectUtils.isEmpty(userId)) {
            GuUser user = userService.getById(userId);
            userInviteVo.setInviteIncome(user.getUserInviteIncome());
            userInviteVo.setLevelExperience(user.getUserInviteIncome());

            //计算用户推广等级
            GuInviteLevel userLevel = inviteLevels.stream().filter(inviteLevel -> user.getUserInviteIncome().compareTo(inviteLevel.getLevelExperience()) >= 0).max(Comparator.comparing(GuInviteLevel::getLevelExperience)).orElse(new GuInviteLevel());
            GuInviteLevel userNextLevel = inviteLevels.stream().filter(inviteLevel -> user.getUserInviteIncome().compareTo(inviteLevel.getLevelExperience()) < 0).min(Comparator.comparing(GuInviteLevel::getLevelExperience)).orElse(new GuInviteLevel());
            userInviteVo.setUserInviteLevel(userLevel.getLevelValue());
            userInviteVo.setMaxLevelExperience(userNextLevel.getLevelExperience());
            userInviteVo.setMinLevelExperience(userLevel.getLevelExperience());
            //用户邀请人数
            userInviteVo.setUserInviteNumber(user.getUserInviteNumber());

            //生成邀请码
//            InviteCodeDto inviteCodeDto = this.getInviteCode(user, systemConfig);
            //存放redis
            userInviteVo.setInviteCode(user.getUserInviteCode());
            userInviteVo.setInviteUrl(systemConfig.getConfigUri() + "/" + user.getUserInviteCode());
            userInviteVo.setExpirationTime(user.getUserInviteExp());

            //处理邀请人奖励列表
            this.disposeInviteNums(user, inviteNums);
        }
        //格式化邀请人数
        userInviteVo.setInviteNumsMap(this.partitionGuInviteNumMap(inviteNums, 6));
        return userInviteVo;
    }

    private List<Map<String, Object>> partitionGuInviteNumMap(final List<GuInviteNum> list, final int size) {
        int limit = (list.size() + size - 1) / size;
        List<Map<String, Object>> mglist = new ArrayList<>();
        Stream.iterate(0, n -> n + 1).limit(limit).forEach(i -> {
            Map<String, Object> map = new HashMap<>();
            List<GuInviteNum> inviteNums = list.stream().skip((long) i * size).limit(size).collect(Collectors.toList());
            map.put("children", inviteNums);
            map.put("min", inviteNums.stream().map(GuInviteNum::getInviteNum).reduce(Integer::min).orElse(0));
            map.put("max", inviteNums.stream().map(GuInviteNum::getInviteNum).reduce(Integer::max).orElse(5));
            mglist.add(map);
        });
        return mglist;
    }

    @Override
    public void receivePrize(Long userId, Integer id) {
        GuUser user = userService.getById(userId);

        GuInviteNum inviteNum = inviteNumService.getById(id);
        switch (inviteNum.getInvitePrizeType()) {
            case PrizeType.BOX:
//                GuBox box = boxService.getBox(inviteNum.getInvitePrizeId());
                //添加库存
                inventoryService.addInventory(user.getUserId(), user.getUserSteamId(), InventoryConstant.Type.BOX, InventoryConstant.Source.PROMOTE, Long.valueOf(inviteNum.getId()), inviteNum.getInvitePrizeId(), null);
                recordService.addRecord(user.getUserId(), RecordConstant.TYPE.GAIN,  InventoryConstant.Source.PROMOTE, inviteNum.getId(), PrizeType.BOX, inviteNum.getInvitePrizeId(), "等级奖励领取奖品", inviteNum.getId().toString());
                break;
            case PrizeType.GOODS:
                inventoryService.addInventory(userId, null, InventoryConstant.Type.GOODS, InventoryConstant.Source.PROMOTE, Long.valueOf(inviteNum.getId()), inviteNum.getInvitePrizeId(), null);
                recordService.addRecord(userId, RecordConstant.TYPE.GAIN, InventoryConstant.Source.PROMOTE, inviteNum.getId(), PrizeType.BOX, inviteNum.getInvitePrizeId(),"兑换集市奖励领取奖品", inviteNum.getId().toString());
                break;
            case PrizeType.PROP:
                propNumService.addPropNum(userId, inviteNum.getInvitePrizeId());
                recordService.addRecord(user.getUserId(), RecordConstant.TYPE.GAIN, InventoryConstant.Source.PROMOTE, inviteNum.getId(), PrizeType.PROP, inviteNum.getInvitePrizeId(),  "等级奖励领取奖品", inviteNum.getId().toString());
                break;
            default:
                throw new GlobalMsgException("参数错误");
        }
    }

    /**
     * 处理邀请人数的奖品
     */
    private void disposeInviteNums(GuUser user, List<GuInviteNum> inviteNums) {
        List<GuRecord> records = recordService.list(new LambdaQueryWrapper<GuRecord>() {
            {
                eq(GuRecord::getRecordUserId, user.getUserId());
                eq(GuRecord::getRecordSourceType, InventoryConstant.Source.PROMOTE);
            }
        });
        inviteNums.stream().filter(inviteNum -> inviteNum.getInviteNum().compareTo(user.getUserInviteNumber()) <= 0).forEach(inviteNum -> {
            inviteNum.setState(1);
            if (!ObjectUtils.isEmpty(inviteNum.getInvitePrizeId())) {
                inviteNum.setPrizeState(1);
                //判断是否已领取
                if (records.stream().anyMatch(record -> Long.valueOf(inviteNum.getId()).equals(record.getRecordSourceId()))) {
                    inviteNum.setPrizeState(2);
                }
            }
        });
    }

    /**
     * 获取奖品图，并添加空奖励等级
     */
    private List<GuInviteNum> initInviteNums(List<GuInviteNum> inviteNums) {
        int maxNum = inviteNums.stream().map(GuInviteNum::getInviteNum).max(Comparator.naturalOrder()).orElse(5);
        Map<Integer, GuInviteNum> inviteNumMap = inviteNums.stream().collect(Collectors.toMap(GuInviteNum::getInviteNum, inviteNum -> inviteNum));
        List<GuInviteNum> inviteNumList = new ArrayList<>(maxNum);
        for (int i = 0; i <= maxNum; i++) {
            GuInviteNum inviteNum = new GuInviteNum();
            inviteNum.setInviteNum(i);
            if (!ObjectUtils.isEmpty(inviteNumMap.get(i))) {
                inviteNum = inviteNumMap.get(i);
                switch (inviteNum.getInvitePrizeType()) {
                    case PrizeType.BOX:
                        GuBox box = boxService.getBox(inviteNum.getInvitePrizeId());
                        inviteNum.setPrizeImage(box.getBoxImageUrl());
                        inviteNum.setPrizeGoodsImage(box.getGoodsList().stream().max(Comparator.comparing(GuGoods::getGoodsPrice)).orElse(new GuGoods()).getGoodsIconUrl());
                        break;
                    case PrizeType.GOODS:
                        GuGoods goods = goodsService.getById(inviteNum.getInvitePrizeId());
                        inviteNum.setPrizeImage(goods.getGoodsIconUrl());
                        break;
                    case PrizeType.PROP:
                        GuProp prop = propService.getById(inviteNum.getInvitePrizeId());
                        inviteNum.setPrizeImage(prop.getPropImage());
                        break;
                    default:
                        break;
//                        throw new GlobalMsgException("系统错误");
                }
                inviteNum.setPrizeState(0);
            }
            inviteNum.setState(0);
            inviteNumList.add(inviteNum);
        }
        return inviteNumList;
    }

    /**
     * 获取推广码
     */
    /*private InviteCodeDto getInviteCode(GuUser user, GuSystemConfig systemConfig) {
        String code;
        //获取redis中
        if (!RedisUtil.hasKey(RedisConstant.USER_INVITE_USER_ID_PREFIX + user.getUserId())) {
            // 生成验证码
            code = ((int) (Math.random() * 999999)) + "";
            RedisUtil.setKey(RedisConstant.USER_INVITE_USER_ID_PREFIX + user.getUserId(), code, systemConfig.getConfigInviteCodeExp(), TimeUnit.DAYS);
            RedisUtil.setKey(RedisConstant.USER_INVITE_CODE_PREFIX + code, JSON.toJSONString(user), systemConfig.getConfigInviteCodeExp(), TimeUnit.DAYS);
        } else {
            code = RedisUtil.getValue(RedisConstant.USER_INVITE_USER_ID_PREFIX + user.getUserId());
        }
        //获取过期值
        Long expire = RedisUtil.getExpire(RedisConstant.USER_INVITE_USER_ID_PREFIX + user.getUserId());

        long expireTime = System.currentTimeMillis() + (expire * 1000);
        String dataAddSecond = DateUtil.milliTimeToString(expireTime, "yyyy-MM-dd HH:mm:ss");

        return InviteCodeDto.builder().inviteCode(code).expirationTime(dataAddSecond).expiration(expire).build();
    }*/

    /**
     * 初始化数据
     */
    private void initUserInviteVo(UserInviteVo userInviteVo, List<GuInviteLevel> inviteLevels) {
        userInviteVo.setMinLevelExperience(inviteLevels.stream().min(Comparator.comparing(GuInviteLevel::getLevelExperience)).orElse(new GuInviteLevel()).getLevelExperience());
        List<GuInviteLevel> collect = inviteLevels.stream().sorted(Comparator.comparing(GuInviteLevel::getLevelExperience)).collect(Collectors.toList());
        BigDecimal experience = collect.size() >= 2 ? collect.get(1).getLevelExperience() : new BigDecimal(10000);
        userInviteVo.setMaxLevelExperience(experience);
        userInviteVo.setInviteIncome(BigDecimal.ZERO);
    }
}
